package edu.neumont.MillerK.Android;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.SlidingDrawer;
import android.widget.Toast;

public class MainService extends Service {
	private SharedPreferences sharedPrefs;
	private SharedPreferences.Editor prefsEditor;

	private LocationManager locationManager;
	private LocationListener locationListener;
	private Location lastKnownLocation;

	private Criteria criteria;

	private String emailUsername;
	private String password;
	private String features;
	private String longitude;
	private String latitude;
	private String altitude;
	private String time;
	private String commands;

	private SimpleDateFormat simpleDateFormat;

	private Handler handler;
	private Intent intent;

	private MediaPlayer screamerPlayer;
	private AudioManager audioManager;
	private WifiManager wifiManager;
	private BluetoothAdapter bluetoothAdapter;
	private TelephonyManager telephonyManager;
	private Method dataConnectionSwitchMethod;
	private Class telephonyManagerClass;
	private Object ITelephonyStub;
	private Class ITelephonyClass;

	private final int panicModeIndex = 0;
	private final int screamerModeIndex = 1;
	private final int wifiIndex = 2;
	private final int bluetoothIndex = 3;
	private final int threeGIndex = 4;
	private final int fourGIndex = 5;
	private final int request_enable_bt = 1;

	private boolean screamerOn;
	private boolean done = false;
	private boolean panicOn = false;

	// Unused methods but must be overwritten
	@Override
	public IBinder onBind(Intent arg0) {
		return null;
	}

	@Override
	public void onCreate() {
		simpleDateFormat = new SimpleDateFormat("HH:mm:ss - dd/MM/yyyy");

		criteria = new Criteria();
		criteria.setAccuracy(Criteria.ACCURACY_FINE);
		locationManager = (LocationManager) getApplicationContext()
				.getSystemService(Context.LOCATION_SERVICE);
		wifiManager = (WifiManager) getApplicationContext().getSystemService(
				Context.WIFI_SERVICE);
		bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
		telephonyManager = (TelephonyManager) getApplicationContext()
				.getSystemService(Context.TELEPHONY_SERVICE);
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		sharedPrefs = getSharedPreferences("default", MODE_PRIVATE);
		prefsEditor = sharedPrefs.edit();
		handler = new Handler();
		screamerOn = intent.getExtras().getBoolean("screamerOn");
		createMediaPlayer();
		requestForCommandServlet();
		return START_STICKY;
	}

	public class MainBinder extends Binder {
		public MainService getService() {
			return MainService.this;
		}
	}

	private void requestForCommandServlet() {
		Thread commandServletThread = new Thread() {
			public void run() {
				do {
					try {
						// Create params for connection including 3sec timeout
						// on connection and 5sec timeout on socket
						HttpParams httpParams = new BasicHttpParams();
						int timeoutConnection = 3000;
						int timeoutSocket = 5000;

						// Set the timeouts
						HttpConnectionParams.setConnectionTimeout(httpParams,
								timeoutConnection);
						HttpConnectionParams.setSoTimeout(httpParams,
								timeoutSocket);
						HttpClient httpClient = new DefaultHttpClient(
								httpParams);

						// Create the data entities
						HttpPost post = new HttpPost(
								"http://b3rwyn.dyndns-free.com:8080/MillerK_Capstone_Web-Service/AndroidCommands");
						HttpResponse response;

						// Gets Post data
						emailUsername = sharedPrefs.getString("username", null);
						password = sharedPrefs.getString("password", null);
						features = sharedPrefs.getString("features", null);

						Log.d("MainService", MessageFormat.format(
								"Credentials - email: {0} password: {1}",
								emailUsername, password));

						// Set POST data
						List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(
								2);
						nameValuePairs.add(new BasicNameValuePair(
								"emailUsername", emailUsername));
						nameValuePairs.add(new BasicNameValuePair("password",
								password));
						nameValuePairs.add(new BasicNameValuePair("features",
								features));
						post.setEntity(new UrlEncodedFormEntity(nameValuePairs));

						Log.d("MainService",
								MessageFormat.format("Features: {0}", features));

						// Query the server
						response = httpClient.execute(post);

						// Grabs the command string from response headers and
						// processes them
						commands = (String) response.getHeaders("commands")[0]
								.getValue();
						Log.d("MainService", "Retrieved Commands - " + commands);
						processCommands(commands);
						if (panicOn) {
							requestForLocationServlet();
						}

					} catch (UnsupportedEncodingException e) {
					} catch (ClientProtocolException e) {
					} catch (IOException e) {
					}
					try {
						System.gc();
						Thread.sleep(10000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				} while (!done);
			};
		};
		commandServletThread.start();
	}

	private void processCommands(String commandString) {
		char[] commands = commandString.toCharArray();
		setPanicFeature(commands[panicModeIndex]);
		setScreamerFeature(commands[screamerModeIndex]);
		setWifiFeature(commands[wifiIndex]);
		setBluetoothFeature(commands[bluetoothIndex]);
		setThreeGFeature(commands[threeGIndex]);
		setFourGFeature(commands[fourGIndex]);
	}

	private void setPanicFeature(char command) {
		if (command == '1') {
			startPanicMode();
			Log.d("LocationService", "Started Service");
		} else if (command == '0') {
			stopPanicMode();
		}
	}

	private void setScreamerFeature(char command) {
		if (command == '1')
			startScreamerMedia();
		else if (command == '0' && screamerOn)
			stopScreamerMedia();
	}

	private void setWifiFeature(char command) {
		if (command == '1')
			enableWifi();
		else if (command == '0')
			disableWifi();
	}

	private void setBluetoothFeature(char command) {
		if (command == '1')
			enableBluetooth();
		else if (command == '0')
			disableBluetooth();
	}

	private void setThreeGFeature(char command) {
		setUpITelephonyClass();
		try {
			if (command == '1') {
				dataConnectionSwitchMethod = ITelephonyClass
						.getDeclaredMethod("enableDataConnectivity");
				invokeDataConnectionSwitchMethod();
			} else if (command == '0') {
				dataConnectionSwitchMethod = ITelephonyClass
						.getDeclaredMethod("disableDataConnectivity");
				invokeDataConnectionSwitchMethod();
			}
		} catch (Exception e) {
			Log.d("Exception", e.getMessage());
		}
	}

	private void setFourGFeature(char command) {
		//TO-DO create 4G feature set up for Galaxy S2 4G Epic Touch
	}

	private void startPanicMode() {
		panicOn = true;
		setFeatures(panicModeIndex, '1');

	}

	private void stopPanicMode() {
		panicOn = false;
		setFeatures(panicModeIndex, '0');
	}

	private void startScreamerMedia() {
		try {
			screamerPlayer.prepare();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		screamerPlayer.start();
		screamerOn = true;
		setFeatures(screamerModeIndex, '1');
	}

	private void stopScreamerMedia() {
		screamerPlayer.stop();
		screamerOn = false;
		setFeatures(screamerModeIndex, '0');
	}

	private void createMediaPlayer() {
		audioManager = (AudioManager) this
				.getSystemService(Context.AUDIO_SERVICE);
		Resources res = getResources();
		AssetFileDescriptor assetFileDescriptor = res
				.openRawResourceFd(R.raw.airhorn);
		int maxVolume = audioManager
				.getStreamMaxVolume(AudioManager.STREAM_ALARM);
		audioManager.setStreamVolume(AudioManager.STREAM_ALARM, maxVolume, 0);
		screamerPlayer = MediaPlayer.create(MainService.this, R.raw.airhorn);
		screamerPlayer.reset();
		screamerPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
		screamerPlayer.setLooping(true);
		try {
			screamerPlayer.setDataSource(
					assetFileDescriptor.getFileDescriptor(),
					assetFileDescriptor.getStartOffset(),
					assetFileDescriptor.getLength());
		} catch (Exception e) {
			Log.d("Exception", e.getMessage());
		}
	}

	public MediaPlayer getScreamerPlayer() {
		createMediaPlayer();
		return screamerPlayer;
	}

	private void enableWifi() {
		wifiManager.setWifiEnabled(true);
		setFeatures(wifiIndex, '1');
	}

	private void disableWifi() {
		wifiManager.setWifiEnabled(false);
		setFeatures(wifiIndex, '0');
	}

	private void enableBluetooth() {
		bluetoothAdapter.enable();
		setFeatures(bluetoothIndex, '1');
	}

	private void disableBluetooth() {
		bluetoothAdapter.disable();
		setFeatures(bluetoothIndex, '0');
	}

	private void setUpITelephonyClass() {
		try {
			telephonyManagerClass = Class.forName(telephonyManager.getClass()
					.getName());
			Method getITelephonyMethod = telephonyManagerClass
					.getDeclaredMethod("getITelephony");
			getITelephonyMethod.setAccessible(true);
			ITelephonyStub = getITelephonyMethod.invoke(telephonyManager);
			ITelephonyClass = Class
					.forName(ITelephonyStub.getClass().getName());
		} catch (Exception e) {
			Log.d("Exception", e.getMessage());
		}
	}
	
	private void invokeDataConnectionSwitchMethod(){
		try {
			dataConnectionSwitchMethod.setAccessible(true);
			dataConnectionSwitchMethod.invoke(ITelephonyStub);
		} catch (Exception e) {
			Log.d("Exception", e.getMessage());
		}
	}

	private void setFeatures(int featureIndex, char setFeature) {
		char[] featureChars = features.toCharArray();
		featureChars[featureIndex] = setFeature;
		prefsEditor.putString("features", new String(featureChars));
		prefsEditor.commit();
	}

	private void requestForLocationServlet() {
		lastKnownLocation = locationManager
				.getLastKnownLocation(locationManager.getBestProvider(criteria,
						true));
		setLocationProperties(lastKnownLocation);
		try {
			// Create params for connection including 3sec timeout
			// on connection and 5sec timeout on socket
			HttpParams httpParams = new BasicHttpParams();
			int timeoutConnection = 3000;
			int timeoutSocket = 5000;

			// Set the timeouts
			HttpConnectionParams.setConnectionTimeout(httpParams,
					timeoutConnection);
			HttpConnectionParams.setSoTimeout(httpParams, timeoutSocket);
			HttpClient httpClient = new DefaultHttpClient(httpParams);

			Log.d("LocationService", "Running!");

			// Create the data entities
			HttpPost post = new HttpPost(
					"http://b3rwyn.dyndns-free.com:8080/MillerK_Capstone_Web-Service/AndroidLocations");
			HttpResponse response;

			// Set POST data
			List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
			nameValuePairs.add(new BasicNameValuePair("emailUsername",
					emailUsername));
			nameValuePairs.add(new BasicNameValuePair("password", password));
			nameValuePairs.add(new BasicNameValuePair("longitude", longitude));
			nameValuePairs.add(new BasicNameValuePair("latitude", latitude));
			nameValuePairs.add(new BasicNameValuePair("altiutde", altitude));
			nameValuePairs.add(new BasicNameValuePair("time", time));
			post.setEntity(new UrlEncodedFormEntity(nameValuePairs));

			Log.d("LocationService", MessageFormat.format(
					"Sending location lat:{0} long:{1} alt:{2} time:{3}",
					longitude, latitude, altitude, time));
			// Query the server and store the user's ID
			response = httpClient.execute(post);
		} catch (UnsupportedEncodingException e) {
		} catch (ClientProtocolException e) {
		} catch (IOException e) {
		}
	}

	private void setLocationProperties(Location location) {
		Log.d("LocationService", "Recieving GPS coordinates");

		longitude = "" + location.getLongitude();
		latitude = "" + location.getLatitude();
		altitude = "" + location.getAltitude();
		time = simpleDateFormat.format(new Date());
	}
}
